home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1998 March / Macworld (1998-03) (Disk 1).dmg / Shareware World / Info / For Developers / GhostScript 5.10 / MacGS-510 / files / gs_fonts.ps < prev    next >
Text File  |  1997-08-08  |  28KB  |  913 lines

  1. %    Copyright (C) 1990, 1995, 1996, 1997 Aladdin Enterprises.  All rights reserved.
  2. % This file is part of Aladdin Ghostscript.
  3. % Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  4. % or distributor accepts any responsibility for the consequences of using it,
  5. % or for whether it serves any particular purpose or works at all, unless he
  6. % or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  7. % License (the "License") for full details.
  8. % Every copy of Aladdin Ghostscript must include a copy of the License,
  9. % normally in a plain ASCII text file named PUBLIC.  The License grants you
  10. % the right to copy, modify and redistribute Aladdin Ghostscript, but only
  11. % under certain conditions described in the License.  Among other things, the
  12. % License requires that the copyright notice and this notice be preserved on
  13. % all copies.
  14.  
  15. % Font initialization and management code.
  16.  
  17. % Define the default font.
  18. /defaultfontname /Courier def
  19.  
  20. % Define the name of the font map file.
  21. /defaultfontmap (Fontmap) def
  22.  
  23. % ------ End of editable parameters ------ %
  24.  
  25. % If SUBSTFONT is defined, make it the default font.
  26. /SUBSTFONT where { pop /defaultfontname /SUBSTFONT load def } if
  27.  
  28. % Define a reliable way of accessing FontDirectory in systemdict.
  29. /.FontDirectory
  30. { //systemdict /FontDirectory get
  31. } bind odef
  32.  
  33. % If DISKFONTS is true, we load individual CharStrings as they are needed.
  34. % (This is intended primarily for machines with very small memories.)
  35. % In this case, we define another dictionary, parallel to FontDirectory,
  36. % that retains an open file for every font loaded.
  37. /FontFileDirectory 10 dict def
  38.  
  39. % Define a temporary string for local use, since using =string
  40. % interferes with some PostScript programs.
  41. /.fonttempstring 128 string def
  42.  
  43. % Split up a search path into individual directories or files.
  44. /.pathlist        % <path> .pathlist <dir1|file1> ...
  45.  {  { dup length 0 eq { pop exit } if
  46.       .filenamelistseparator search not { exit } if
  47.       exch pop exch
  48.     }
  49.    loop
  50.  } bind def
  51.  
  52. % Load a font name -> font file name map.
  53. userdict /Fontmap .FontDirectory maxlength dict put
  54. /.loadFontmap        % <file> .loadFontmap -
  55.  {        % We would like to simply execute .definefontmap as we read,
  56.         % but we have to maintain backward compatibility with an older
  57.         % specification that makes later entries override earlier.
  58.    50 dict exch
  59.     { dup token not { closefile exit } if
  60.         % stack: <file> fontname
  61.       % This is a hack to get around the absurd habit of MS-DOS editors
  62.       % of adding an EOF character at the end of the file.
  63.       dup (\032) eq { pop closefile exit } if
  64.       1 index token not
  65.        { (Fontmap entry for ) print dup =only
  66.      ( has no associated file or alias name!  Giving up.\n) print flush
  67.      {.loadFontmap} 0 get 1 .quit
  68.        } if
  69.       dup type dup /stringtype eq exch /nametype eq or not
  70.        { (Fontmap entry for ) print 1 index =only
  71.      ( has an invalid file or alias name!  Giving up.\n) print flush
  72.      {.loadFontmap} 0 get 1 .quit
  73.        } if
  74.         % stack: dict file fontname filename|aliasname
  75.         % Read and pop tokens until a semicolon.
  76.        { 2 index token not
  77.       { (Fontmap entry for ) print 1 index =only
  78.         ( ends prematurely!  Giving up.\n) print flush
  79.         {.loadFontmap} 0 get 1 .quit
  80.       } if
  81.      dup /; eq { pop 3 index 3 1 roll .growput exit } if
  82.      pop
  83.        } loop
  84.     } loop
  85.     { .definefontmap } forall
  86.  } bind def
  87. % Add an entry in Fontmap.  We redefine this if the Level 2
  88. % resource machinery is loaded.
  89. /.definefontmap            % <fontname> <file|alias> .definefontmap -
  90.  {        % Since Fontmap is global, make sure the values are storable.
  91.    .currentglobal 3 1 roll true .setglobal
  92.    dup type /stringtype eq
  93.     { dup .gcheck not { dup length string copy } if
  94.     }
  95.    if
  96.    Fontmap 3 -1 roll 2 copy .knownget
  97.     {        % Add an element to the end of the existing value,
  98.         % unless it's the same as the current last element.
  99.       mark exch aload pop counttomark 4 add -1 roll
  100.       2 copy eq { cleartomark pop pop } { ] readonly .growput } ifelse
  101.     }
  102.     {        % Make a new entry.
  103.       mark 4 -1 roll ] readonly .growput
  104.     }
  105.    ifelse .setglobal
  106.  } bind def
  107.  
  108. % Parse a font file just enough to find the FontName or FontType.
  109. /.findfontvalue        % <file> <key> .findfontvalue <value> true
  110.             % <file> <key> .findfontvalue false
  111.             % Closes the file in either case.
  112.  { exch dup read not { -1 } if
  113.    2 copy unread 16#80 eq
  114.     { dup (xxxxxx) readstring pop pop }        % skip .PFB header
  115.    if
  116.         % Stack: key file
  117.     { dup token not { false exit } if        % end of file
  118.       dup /eexec eq { pop false exit } if    % reached eexec section
  119.       dup /Subrs eq { pop false exit } if    % Subrs without eexec
  120.       dup /CharStrings eq { pop false exit } if    % CharStrings without eexec
  121.       dup 3 index eq
  122.        { xcheck not { dup token exit } if }    % found key
  123.        { pop }
  124.       ifelse
  125.     } loop
  126.         % Stack: key file value true   (or)
  127.         % Stack: key file false
  128.    dup { 4 } { 3 } ifelse -2 roll closefile pop
  129.  } bind def
  130. /.findfontname
  131.  { /FontName .findfontvalue
  132.  } bind def
  133.  
  134. % If there is no FONTPATH, try to get one from the environment.
  135. NOFONTPATH { /FONTPATH () def } if
  136. /FONTPATH where
  137.  { pop }
  138.  { /FONTPATH (GS_FONTPATH) getenv not { () } if def }
  139. ifelse
  140. FONTPATH length 0 eq { (%END FONTPATH) .skipeof } if
  141. /FONTPATH [ FONTPATH .pathlist ] def
  142.  
  143. % Scan directories looking for plausible fonts.  "Plausible" means that
  144. % the file begins with %!PS-AdobeFont or %!FontType1, or with \200\001
  145. % followed by four arbitrary bytes and then either of these strings.
  146. % To speed up the search, we skip any file whose name appears in
  147. % the Fontmap (with any extension and upper/lower case variation) already,
  148. % and any file whose extension definitely indicates it is not a font.
  149. %
  150. % NOTE: The current implementation of this procedure is somewhat Unix/DOS-
  151. % specific.  It assumes that '/' and '\' are directory separators, and that
  152. % the part of a file name following the last '.' is the extension.
  153. %
  154. /.lowerstring        % <string> .lowerstring <lowerstring>
  155.  { 0 1 2 index length 1 sub
  156.     { 2 copy get dup 65 ge exch 90 le and
  157.        { 2 copy 2 copy get 32 add put }
  158.      if pop
  159.     }
  160.    for
  161.  } bind def
  162. /.splitfilename        % <dir.../base.extn> .basename <base> <extn>
  163.  {  { (/) search { true } { (\\) search } ifelse
  164.        { pop pop }
  165.        { exit }
  166.       ifelse
  167.     }
  168.    loop
  169.    dup { (.) search { pop pop } { exit } ifelse } loop
  170.    2 copy eq
  171.     { pop () }
  172.     { exch dup length 2 index length 1 add sub 0 exch getinterval exch }
  173.    ifelse
  174. % Following is debugging code.
  175. %   (*** Split => ) print 2 copy exch ==only ( ) print ==only
  176. %   ( ***\n) print flush
  177.  } bind def
  178. /.scanfontdict 1 dict def        % establish a binding
  179. /.scanfontbegin
  180.  {    % Construct the table of all file names already in Fontmap.
  181.    currentglobal true setglobal
  182.    .scanfontdict dup maxlength Fontmap length 2 add .max .setmaxlength
  183.    Fontmap
  184.     { exch pop
  185.        { dup type /stringtype eq
  186.       { .splitfilename pop .fonttempstring copy .lowerstring cvn
  187.         .scanfontdict exch true put
  188.       }
  189.       { pop
  190.       }
  191.      ifelse
  192.        }
  193.       forall
  194.     }
  195.    forall
  196.    setglobal
  197.  } bind def
  198. /.scanfontskip mark
  199.         % Strings are converted to names anyway, so....
  200.   /afm true
  201.   /bat true
  202.   /c true
  203.   /cmd true
  204.   /com true
  205.   /dll true
  206.   /doc true
  207.   /drv true
  208.   /exe true
  209.   /fon true
  210.   /fot true
  211.   /h true
  212.   /o true
  213.   /obj true
  214.   /pfm true
  215.   /pss true        % Adobe Multiple Master font instances
  216.   /txt true
  217. .dicttomark def
  218. /.scan1fontstring 128 string def
  219. /.scanfontheaders [(%!PS-Adobe*) (%!FontType*)] def
  220. 0 .scanfontheaders { length max } forall 6 add    % extra for PFB header
  221. /.scan1fontfirst exch string def
  222. /.scanfontdir        % <dirname> .scanfontdir -
  223.  { currentglobal exch true setglobal
  224.    QUIET not { (Scanning ) print dup print ( for fonts...) print flush } if
  225.    (*) 2 copy .filenamedirseparator
  226.    dup (\\) eq { pop (\\\\) } if    % double \ for pattern match
  227.    exch concatstrings concatstrings
  228.    0 0 0 4 -1 roll    % found scanned files
  229.     {        % stack: <fontcount> <scancount> <filecount> <filename>
  230.       exch 1 add exch                   % increment filecount
  231.       dup .splitfilename .lowerstring
  232.         % stack: <fontcount> <scancount> <filecount+1> <filename>
  233.         %    <BASE> <ext>
  234.       .scanfontskip exch known exch .scanfontdict exch known or
  235.        { pop
  236.         % stack: <fontcount> <scancount> <filecount+1>
  237.        }
  238.        { 3 -1 roll 1 add 3 1 roll
  239.         % stack: <fontcount> <scancount+1> <filecount+1> <filename>
  240.      dup (r) { file } .internalstopped
  241.       { pop pop null ()
  242.         % stack: <fontcount> <scancount+1> <filecount+1> <filename>
  243.         %    null ()
  244.       }
  245.       {
  246.         % On some platforms, the file operator will open directories,
  247.         % but an error will occur if we try to read from one.
  248.         % Handle this possibility here.
  249.         dup .scan1fontfirst { readstring } .internalstopped
  250.          { pop pop () }
  251.          { pop }
  252.         ifelse
  253.         % stack: <fontcount> <scancount+1> <filecount+1>
  254.         %    <filename> <file> <header>
  255.       }
  256.      ifelse
  257.         % Check for PFB file header.
  258.      dup (\200\001????*) .stringmatch
  259.       { dup length 6 sub 6 exch getinterval }
  260.      if
  261.         % Check for font file headers.
  262.      false .scanfontheaders
  263.       { 2 index exch .stringmatch or
  264.       }
  265.      forall exch pop
  266.       {    % stack: <fontcount> <scancount+1> <filecount+1> <filename>
  267.         %    <file>
  268.         dup 0 setfileposition .findfontname
  269.          { dup Fontmap exch known
  270.         { pop pop
  271.         }
  272.         { exch copystring exch
  273.           DEBUG { ( ) print dup =only } if
  274.           1 index .definefontmap
  275.           .splitfilename pop true .scanfontdict 3 1 roll .growput
  276.             % Increment fontcount.
  277.           3 -1 roll 1 add 3 1 roll
  278.         }
  279.            ifelse
  280.          }
  281.          { pop
  282.          }
  283.         ifelse
  284.       }
  285.         % .findfontname will have done a closefile in the above case.
  286.       { dup null eq { pop } { closefile } ifelse pop
  287.       }
  288.      ifelse
  289.        }
  290.       ifelse
  291.     }
  292.    .scan1fontstring filenameforall
  293.    QUIET
  294.     { pop pop pop }
  295.     { ( ) print =only ( files, ) print =only ( scanned, ) print
  296.       =only ( new fonts.\n) print flush
  297.     }
  298.    ifelse
  299.    setglobal
  300.  } bind def
  301.  
  302. %END FONTPATH
  303.  
  304. % Create the dictionary that registers the .buildfont procedure (called by
  305. % definefont) for each FontType.
  306. /buildfontdict 20 dict def
  307.  
  308. % Register Type 3 fonts, which are always supported, for definefont.
  309. buildfontdict 3 /.buildfont3 cvx put
  310.  
  311. % Register Type 0 fonts if they are supported.  Strictly speaking,
  312. % we should do this in its own file (gs_type0.ps), but since this is
  313. % the only thing that would be in that file, it's simpler to put it here.
  314. /.buildfont0 where { pop buildfontdict 0 /.buildfont0 cvx put } if
  315.  
  316. % Define definefont.  This is a procedure built on a set of operators
  317. % that do all the error checking and key insertion.
  318. /.growfontdict
  319.  {    % Grow the font dictionary, if necessary, to ensure room for an
  320.     % added entry, making sure there is at least one slot left for FID.
  321.    dup maxlength 1 index length sub 2 lt
  322.     { dup dup wcheck
  323.        { .growdict }
  324.        { .growdictlength dict .copydict }
  325.       ifelse
  326.     }
  327.     { dup wcheck not { dup maxlength dict .copydict } if
  328.     }
  329.    ifelse
  330.  } bind def 
  331. /.completefont {
  332.   {        % Check for disabled platform fonts.
  333.       NOPLATFONTS
  334.        {    % Make sure we leave room for FID.
  335.      .growfontdict dup /ExactSize 0 put
  336.        }
  337.        {    % Hack: if the Encoding looks like it might be the
  338.         % Symbol or Dingbats encoding, load those now (for the
  339.         % benefit of platform font matching) just in case
  340.         % the font didn't actually reference them.
  341.      dup /Encoding get length 65 ge
  342.       { dup /Encoding get 64 get
  343.         dup /congruent eq { SymbolEncoding pop } if
  344.         /a9 eq { DingbatsEncoding pop } if
  345.       }
  346.      if
  347.        }
  348.       ifelse
  349.       dup /FontType get //buildfontdict exch get exec
  350.       DISKFONTS
  351.        { FontFileDirectory 2 index known
  352.       { dup /FontFile FontFileDirectory 4 index get .growput
  353.       }
  354.      if
  355.        }
  356.       if
  357.       readonly        % stack: name fontdict
  358.   } stopped { /invalidfont signalerror } if
  359. } bind odef
  360. /definefont
  361.  { .completefont
  362.         % If the current allocation mode is global, also enter
  363.         % the font in LocalFontDirectory.
  364.    .currentglobal
  365.     { //systemdict /LocalFontDirectory .knownget
  366.        { 2 index 2 index .growput }
  367.       if
  368.     }
  369.    if
  370.    dup .FontDirectory 4 -2 roll .growput
  371.  } odef
  372.  
  373. % Define a procedure for defining aliased fonts.
  374. % We can't just copy the font (or even use the same font unchanged),
  375. % because a significant number of PostScript files assume that
  376. % the FontName of a font is the same as the font resource name or
  377. % the key in [Shared]FontDirectory; on the other hand, some Adobe files
  378. % rely on the FontName of a substituted font *not* being the same as
  379. % the requested resource name.  We address this issue heuristically:
  380. % we substitute the new name iff the font name doesn't have MM in it.
  381. /.aliasfont        % <name> <font> .aliasfont <newFont>
  382.  { .currentglobal 3 1 roll dup .gcheck .setglobal
  383.    dup length 2 add dict
  384.    dup 3 -1 roll { 1 index /FID eq { pop pop } { put dup } ifelse } forall
  385.         % Stack: global fontname newfont newfont.
  386.         % We might be defining a global font whose FontName
  387.         % is a local string.  This is weird, but legal,
  388.         % and doesn't cause problems anywhere else:
  389.         % to avoid any possible problems in this case, do a cvn.
  390.         % We might also be defining (as an alias) a global font
  391.         % whose FontName is a local non-string, if someone passed a
  392.         % garbage value to findfont.  In this case, just don't
  393.         % call definefont at all.
  394.    2 index dup type /stringtype eq exch .gcheck or 1 index .gcheck not or
  395.     { 2 index .fonttempstring cvs (MM) search
  396.        { pop pop pop pop
  397.        }
  398.        { /FontName exch dup type /stringtype eq { cvn } if put
  399.        }
  400.       ifelse
  401.         % Don't bind in definefont, since Level 2 redefines it.
  402.       //systemdict /definefont get exec
  403.     }
  404.     { .completefont pop exch pop
  405.     }
  406.    ifelse exch .setglobal
  407.  } odef        % so findfont will bind it
  408.  
  409. % Define .loadfontfile for loading a font.  If we recognize Type 1 and/or
  410. % TrueType fonts, gs_type1.ps and/or gs_ttf.ps will redefine this.
  411. /.loadfontfile { cvx exec } bind def
  412. /.loadfont
  413.  {        % Some buggy fonts leave extra junk on the stack,
  414.         % so we have to make a closure that records the stack depth
  415.         % in a fail-safe way.
  416.    /.loadfontfile cvx count 1 sub 2 packedarray cvx exec
  417.    count exch sub { pop } repeat
  418.  } bind def
  419.  
  420. % Find an alternate font to substitute for an unknown one.
  421. % We go to some trouble to parse the font name and extract
  422. % properties from it.  Later entries take priority over earlier.
  423. /.substitutefaces [
  424.     % Guess at suitable substitutions for random unknown fonts.
  425.   [(Grot) /Times]
  426.   [(Roman) /Times]
  427.   [(Book) /NewCenturySchlbk]
  428.     % If the family name appears in the font name,
  429.     % use a font from that family.
  430.   [(Arial) /Helvetica]
  431.   [(Avant) /AvantGarde]
  432.   [(Bookman) /Bookman]
  433.   [(Century) /NewCenturySchlbk]
  434.   [(Cour) /Courier]
  435.   [(Geneva) /Helvetica]
  436.   [(Helv) /Helvetica]
  437.   [(NewYork) /Times]
  438.   [(Pala) /Palatino]
  439.   [(Sans) /Helvetica]
  440.   [(Schlbk) /NewCenturySchlbk]
  441.   [(Serif) /Times]
  442.   [(Swiss) /Helvetica]
  443.   [(Times) /Times]
  444.   [(Univers) /Helvetica]
  445.     % Substitute for Adobe Multiple Master fonts.
  446.   [(Minion) /Times]
  447.   [(Myriad) /Helvetica]
  448.   [(MyriadPkg) /Helvetica-Narrow]
  449.     % Condensed or narrow fonts map to the only narrow family we have.
  450.   [(Cond) /Helvetica-Narrow]
  451.   [(Narrow) /Helvetica-Narrow]
  452.     % If the font wants to be monospace, use Courier.
  453.   [(Monospace) /Courier]
  454.   [(Typewriter) /Courier]
  455. ] readonly def
  456. /.substituteproperties [
  457.   [(It) 1] [(Oblique) 1]
  458.   [(Bd) 2] [(Bold) 2] [(bold) 2] [(Demi) 2] [(Heavy) 2] [(Sb) 2]
  459. ] readonly def
  460. /.substitutefamilies mark
  461.   /AvantGarde
  462.     {/AvantGarde-Book /AvantGarde-BookOblique
  463.      /AvantGarde-Demi /AvantGarde-DemiOblique}
  464.   /Bookman
  465.     {/Bookman-Demi /Bookman-DemiItalic /Bookman-Light /Bookman-LightItalic}
  466.   /Courier
  467.     {/Courier /Courier-Oblique /Courier-Bold /Courier-BoldOblique}
  468.   /Helvetica
  469.     {/Helvetica /Helvetica-Oblique /Helvetica-Bold /Helvetica-BoldOblique}
  470.   /Helvetica-Narrow
  471.     {/Helvetica-Narrow /Helvetica-Narrow-Oblique
  472.      /Helvetica-Narrow-Bold /Helvetica-Narrow-BoldOblique}
  473.   /NewCenturySchlbk
  474.     {/NewCenturySchlbk-Roman /NewCenturySchlbk-Italic
  475.      /NewCenturySchlbk-Bold /NewCenturySchlbk-BoldItalic}
  476.   /Palatino
  477.     {/Palatino-Roman /Palatino-Italic /Palatino-Bold /Palatino-BoldItalic}
  478.   /Times
  479.     {/Times-Roman /Times-Italic /Times-Bold /Times-BoldItalic}
  480. .dicttomark readonly def
  481. /.substitutefont        % <fontname> .substitutefont <altname>
  482.  {    % Look for properties and/or a face name in the font name.
  483.     % If we find any, use Helvetica as the base font;
  484.     % otherwise, use the default font.
  485.     % Note that the "substituted" font name may be the same as
  486.     % the requested one; the caller must check this.
  487.    dup type dup /stringtype eq exch /nametype eq or
  488.     { dup length string cvs } { () } ifelse
  489.     {defaultfontname /Helvetica-Oblique /Helvetica-Bold /Helvetica-BoldOblique}
  490.    exch 0 exch    % stack: fontname facelist properties fontname
  491.     % Look for a face name.
  492.    .substitutefaces
  493.     { 2 copy 0 get search
  494.        { pop pop pop 1 get .substitutefamilies exch get
  495.      4 -1 roll pop 3 1 roll
  496.        }
  497.        { pop pop
  498.        }
  499.       ifelse
  500.     }
  501.    forall
  502.    .substituteproperties
  503.     { 2 copy 0 get search
  504.        { pop pop pop 1 get 3 -1 roll or exch }
  505.        { pop pop }
  506.       ifelse
  507.     }
  508.    forall pop get exec
  509.     % Only accept fonts known in the Fontmap.
  510.    Fontmap 1 index known not { pop defaultfontname } if
  511.  } bind def
  512.  
  513. % If requested, make (and recognize) fake entries in FontDirectory for fonts
  514. % present in Fontmap but not actually loaded.  Thanks to Ray Johnston for
  515. % the idea behind this code.
  516. FAKEFONTS not { (%END FAKEFONTS) .skipeof } if
  517.  
  518. % We use the presence or absence of the FontMatrix key to indicate whether
  519. % a font is real or fake.  We must pop the arguments at the very end,
  520. % so that stack protection will be effective.
  521.  
  522. /definefont {        % <name> <font> definefont <font>
  523.   dup /FontMatrix known {
  524.     //definefont
  525.   } {
  526.     2 copy /FontName get findfont //definefont exch pop exch pop
  527.   } ifelse
  528. } bind odef
  529.  
  530. /scalefont {        % <font> <scale> scalefont <font>
  531.   1 index /FontMatrix known {
  532.     //scalefont
  533.   } {
  534.     1 index /FontName get findfont 1 index //scalefont
  535.     exch pop exch pop
  536.   } ifelse
  537. } bind odef
  538.  
  539. /makefont {        % <font> <matrix> makefont <font>
  540.   1 index /FontMatrix known {
  541.     //makefont
  542.   } {
  543.     1 index /FontName get findfont 1 index //makefont
  544.     exch pop exch pop
  545.   } ifelse
  546. } bind odef
  547.  
  548. /setfont {        % <font> setfont -
  549.   dup /FontMatrix known {
  550.     //setfont
  551.   } {
  552.     dup /FontName get findfont //setfont pop
  553.   } ifelse
  554. } bind odef
  555.  
  556. %END FAKEFONTS
  557.  
  558. % Define findfont so it tries to load a font if it's not found.
  559. % The Red Book requires that findfont be a procedure, not an operator,
  560. % but it still needs to restore the stacks reliably if it fails,
  561. % so we do all the work in an operator.
  562. /.findfont {
  563.   mark 1 index
  564.   //systemdict begin .dofindfont
  565.     % Define any needed aliases.
  566.   counttomark 1 sub { .aliasfont } repeat end
  567.   exch pop exch pop
  568. } odef
  569. /findfont {
  570.   .findfont
  571. } bind def
  572. % Check whether the font name we are about to look for is already on the list
  573. % of aliases we're accumulating; if so, cause an error.
  574. /.checkalias        % -mark- <alias1> ... <name> .checkalias <<same>>
  575.  { counttomark 1 sub -1 1
  576.     { index 1 index eq
  577.        { pop QUIET not
  578.       { (Unable to substitute for font.\n) print flush
  579.       } if
  580.      /findfont cvx /invalidfont signalerror
  581.        }
  582.       if
  583.     }
  584.    for
  585.  } bind def
  586. % Get a (non-fake) font if present in a FontDirectory.
  587. /.fontknownget        % <fontdir> <fontname> .fontknownget <font> true
  588.             % <fontdir> <fontname> .fontknownget false
  589.  { .knownget
  590.     { FAKEFONTS
  591.        { dup /FontMatrix known { true } { pop false } ifelse }
  592.        { true }
  593.       ifelse
  594.     }
  595.     { false
  596.     }
  597.    ifelse
  598.  } bind def
  599. % Do the work of findfont, including substitution, defaulting, and
  600. % scanning of FONTPATH.
  601. /.dofindfont        % <fontname> .dofindfont <font>
  602.  {  { .tryfindfont { exit } if
  603.             % We didn't find the font.  If we haven't scanned
  604.             % all the directories in FONTPATH, scan the next one now,
  605.             % and look for the font again.
  606.       null 0 1 FONTPATH length 1 sub
  607.        { FONTPATH 1 index get null ne { exch pop exit } if pop
  608.        }
  609.       for dup null ne
  610.        { dup 0 eq { .scanfontbegin } if
  611.      FONTPATH 1 index get .scanfontdir
  612.      FONTPATH exch null put
  613.             % Start over with an empty alias list.
  614.      counttomark 1 sub { pop } repeat
  615.      .dofindfont exit
  616.        }
  617.       if pop
  618.             % No luck.  Make sure we're not already
  619.             % looking for the default font.
  620.       dup defaultfontname eq
  621.        { QUIET not
  622.       { (Unable to load default font ) print
  623.         dup =only (!  Giving up.\n) print flush
  624.       }
  625.      if /findfont cvx /invalidfont signalerror
  626.        }
  627.       if
  628.             % Substitute for the font.
  629.             % If SUBSTFONT is defined, don't alias.
  630.       /SUBSTFONT where {
  631.     pop QUIET not {
  632.       (Substituting for font ) print dup =only
  633.       (.\n) print flush
  634.     } if
  635.     cleartomark mark defaultfontname
  636.       } {
  637.     dup .substitutefont
  638.     2 copy eq { pop defaultfontname } if
  639.     .checkalias
  640.     QUIET not {
  641.       (Substituting font ) print dup =only ( for ) print
  642.       1 index =only (.\n) print flush
  643.     } if
  644.       } ifelse
  645.     }
  646.    loop
  647.  } bind def
  648. % Try to find a font using only the present contents of Fontmap.
  649. /.tryfindfont        % <fontname> .tryfindfont <font> true
  650.             % <fontname> .tryfindfont false
  651.  { .FontDirectory 1 index .fontknownget
  652.     {            % Already loaded
  653.       exch pop true
  654.     }
  655.     { dup Fontmap exch .knownget not
  656.        {        % Unknown font name.  Look for a file with the
  657.             % same name as the requested font.
  658.      dup dup type /nametype eq { .namestring } if .loadfontloop
  659.        }
  660.        {        % Try each element of the Fontmap in turn.
  661.      false exch    % (in case we exhaust the list)
  662.             % Stack: fontname false fontmaplist
  663.      { exch pop
  664.        dup type /nametype eq
  665.         {            % Font alias
  666.           .checkalias .tryfindfont exit
  667.         }
  668.         { dup dup type dup /arraytype eq exch /packedarraytype eq or exch xcheck and
  669.            {        % Font with a procedural definition
  670.          exec        % The procedure will load the font.
  671.                 % Check to make sure this really happened.
  672.          .FontDirectory 1 index .knownget
  673.           { exch pop true exit }
  674.          if
  675.            }
  676.            {        % Font file name
  677.          .loadfontloop { true exit } if
  678.            }
  679.           ifelse
  680.         }
  681.        ifelse false
  682.      }
  683.      forall
  684.             % Stack: font true -or- fontname false
  685.      { true
  686.      }
  687.      {            % None of the Fontmap entries worked.
  688.                 % Try loading a file with the same name
  689.                 % as the requested font.
  690.        dup dup type /nametype eq { .namestring } if .loadfontloop
  691.      }
  692.     ifelse
  693.        }
  694.       ifelse
  695.     }
  696.    ifelse
  697.  } bind def
  698. % Attempt to load a font from a file.
  699. /.loadfontloop        % <filename> .loadfontloop <font> true
  700.             % <filename> .loadfontloop false
  701.  {            % See above regarding the use of 'loop'.
  702.  
  703.     {
  704.             % Is the font name a string?
  705.     dup type /stringtype ne
  706.      { QUIET not
  707.         { (Can't find font with non-string name: ) print dup =only (.\n) print flush
  708.         }
  709.        if pop false exit
  710.      }
  711.     if
  712.             % Can we open the file?
  713.     findlibfile not
  714.      { QUIET not
  715.         { (Can't find \(or can't open\) font file ) print dup print
  716.           (.\n) print flush
  717.         }
  718.        if pop false exit
  719.      }
  720.     if
  721.  
  722.             % Stack: fontname fontfilename fontfile
  723.     DISKFONTS
  724.      { .currentglobal true .setglobal
  725.        2 index (r) file
  726.        FontFileDirectory exch 5 index exch .growput
  727.        .setglobal
  728.      }
  729.     if
  730.     QUIET not
  731.      { (Loading ) print 2 index =only
  732.        ( font from ) print 1 index print (... ) print flush
  733.      }
  734.     if
  735.     % If LOCALFONTS isn't set, load the font into local or global
  736.     % VM according to FontType; if LOCALFONTS is set, load the font
  737.     % into the current VM, which is what Adobe printers (but not
  738.     % DPS or CPSI) do.
  739.     LOCALFONTS { false } { /setglobal where } ifelse
  740.      { pop /FontType .findfontvalue { 1 eq } { false } ifelse
  741.         % .setglobal, like setglobal, aliases FontDirectory to
  742.         % GlobalFontDirectory if appropriate.  However, we mustn't
  743.         % allow the current version of .setglobal to be bound in,
  744.         % because it's different depending on language level.
  745.        .currentglobal exch /.setglobal load exec
  746.         % Remove the fake definition, if any.
  747.        .FontDirectory 3 index .undef
  748.        1 index (r) file .loadfont .FontDirectory exch
  749.        /.setglobal load exec
  750.      }
  751.      { .loadfont .FontDirectory
  752.      }
  753.     ifelse
  754.         % Stack: fontname fontfilename fontdirectory
  755.     QUIET not
  756.      { //systemdict /level2dict known
  757.         { .currentglobal false .setglobal vmstatus
  758.           true .setglobal vmstatus 3 -1 roll pop
  759.           6 -1 roll .setglobal 5
  760.         }
  761.         { vmstatus 3
  762.         }
  763.        ifelse { =only ( ) print } repeat
  764.        (done.\n) print flush
  765.      } if
  766.  
  767.         % Check to make sure the font was actually loaded.
  768.     dup 3 index .fontknownget
  769.      { 4 1 roll pop pop pop true exit } if
  770.  
  771.         % Maybe the file had a different FontName.
  772.         % See if we can get a FontName from the file, and if so,
  773.         % whether a font by that name exists now.
  774.     exch (r) file .findfontname
  775.      { 2 copy .fontknownget
  776.         {    % Yes.  Stack: origfontname fontdirectory filefontname fontdict
  777.           3 -1 roll pop exch
  778.           QUIET
  779.            { pop
  780.            }
  781.            { (Using ) print =only
  782.              ( font for ) print 1 index =only
  783.              (.\n) print flush
  784.            }
  785.           ifelse true exit
  786.         }
  787.        if pop
  788.      }
  789.     if pop
  790.  
  791.         % The font definitely did not load correctly.
  792.     QUIET not
  793.      { (Loading ) print dup =only
  794.        ( font failed.\n) print flush
  795.      } if
  796.     false exit
  797.  
  798.     } loop        % end of loop
  799.  
  800.  } bind def
  801.  
  802. % Define a procedure to load all known fonts.
  803. % This isn't likely to be very useful.
  804. /loadallfonts
  805.  { Fontmap { pop findfont pop } forall
  806.  } bind def
  807.  
  808. % If requested, load all the fonts defined in the Fontmap into FontDirectory
  809. % as "fake" fonts i.e., font dicts with only FontName and FontType defined.
  810. % (We define FontType only to for the sake of some questionable code in the
  811. % Apple Printer Utility 2.0 font inquiry code.) We must ensure that this
  812. % happens in both global and local directories.
  813. /.definefakefonts
  814.     {
  815.     }
  816.     { (gs_fonts FAKEFONTS) VMDEBUG
  817.       2
  818.     { .currentglobal not .setglobal
  819.       Fontmap
  820.        { pop dup type /stringtype eq { cvn } if
  821.          .FontDirectory 1 index known not
  822.           { 2 dict dup /FontName 3 index put
  823.         dup /FontType 1 put
  824.             .FontDirectory 3 1 roll put
  825.           }
  826.           { pop
  827.           }
  828.          ifelse
  829.        }
  830.       forall
  831.        }
  832.       repeat
  833.     }
  834. FAKEFONTS { exch } if pop def        % don't bind, .current/setglobal get redefined
  835.  
  836. % Install initial fonts from Fontmap.
  837. /.loadinitialfonts
  838.  { NOFONTMAP not
  839.     { /FONTMAP where
  840.       { pop [ FONTMAP .pathlist ]
  841.          { dup VMDEBUG findlibfile
  842.         { exch pop .loadFontmap }
  843.         { /undefinedfilename signalerror }
  844.            ifelse
  845.          }
  846.       }
  847.       { LIBPATH
  848.          { defaultfontmap 2 copy .filenamedirseparator
  849.            exch concatstrings concatstrings dup VMDEBUG
  850.            (r) { file } .internalstopped
  851.         { pop pop } { .loadFontmap } ifelse
  852.          }
  853.       }
  854.      ifelse forall
  855.     }
  856.    if
  857.    .definefakefonts
  858.  } def            % don't bind, .current/setglobal get redefined
  859.  
  860. % ---------------- Synthetic font support ---------------- %
  861.  
  862. % Create a new font by modifying an existing one.  paramdict contains
  863. % entries with the same keys as the ones found in a Type 1 font;
  864. % it should also contain enough empty entries to allow adding the
  865. % corresponding non-overridden entries from the original font dictionary,
  866. % including FID.  If paramdict includes a FontInfo entry, this will
  867. % also override the original font's FontInfo, entry by entry;
  868. % again, it must contain enough empty entries.
  869.  
  870. % Note that this procedure does not perform a definefont.
  871.  
  872. /.makemodifiedfont    % <fontdict> <paramdict> .makemodifiedfont <fontdict'>
  873.  { exch
  874.     {            % Stack: destdict key value
  875.       1 index /FID ne
  876.        { 2 index 2 index known
  877.       {        % Skip fontdict entry supplied in paramdict, but
  878.             % handle FontInfo specially.
  879.         1 index /FontInfo eq
  880.          { 2 index 2 index get        % new FontInfo
  881.            1 index                % old FontInfo
  882.         {    % Stack: destdict key value destinfo key value
  883.           2 index 2 index known
  884.            { pop pop }
  885.            { 2 index 3 1 roll put }
  886.           ifelse
  887.         }
  888.            forall pop
  889.          }
  890.         if
  891.       }
  892.       {        % No override, copy the fontdict entry.
  893.         2 index 3 1 roll put
  894.         dup dup    % to match pop pop below
  895.       }
  896.      ifelse
  897.        }
  898.       if
  899.       pop pop
  900.     } forall
  901.  } bind def
  902.  
  903. % Make a modified font and define it.  Note that unlike definefont,
  904. % this does not leave the font on the operand stack.
  905.  
  906. /.definemodifiedfont    % <fontdict> <paramdict> .definemodifiedfont -
  907.  { .makemodifiedfont
  908.    dup /FontName get exch definefont pop
  909.  } bind def
  910.